package com.xiao.code.parse;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import japa.parser.JavaParser;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.Node;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.visitor.VoidVisitorAdapter;

/**
 * java 描述文件
 * @author Administrator
 * @param <A>
 *
 */
public class JavaDescribe {
	
	File file;
	
    // 报名
	String packgeName;
	
	// 所属项目名
	String poolName;
	
	// 模块名
	String modelName;
	
	// 类名 简单
	String claName;
	
	// 存入map的key
	String key;
	
	private List<String> utilsList = Arrays.asList("AbstractMethodError","AbstractStringBuilder","Appendable","ApplicationShutdownHooks","ArithmeticException","ArrayIndexOutOfBoundsException","ArrayStoreException","AssertionError","AssertionStatusDirectives","AutoCloseable","Boolean","BootstrapMethodError","Byte","Character","CharacterData","CharacterData00","CharacterData01","CharacterData02","CharacterData0E","CharacterDataLatin1","CharacterDataPrivateUse","CharacterDataUndefined","CharacterName","CharSequence","Class","ClassCastException","ClassCircularityError","ClassFormatError","ClassLoader","ClassLoaderHelper","ClassNotFoundException","ClassValue","Cloneable","CloneNotSupportedException","Comparable","Compiler","ConditionalSpecialCasing","Deprecated","Double","Enum","EnumConstantNotPresentException","Error","Exception","ExceptionInInitializerError","Float","FunctionalInterface","IllegalAccessError","IllegalAccessException","IllegalArgumentException","IllegalMonitorStateException","IllegalStateException","IllegalThreadStateException","IncompatibleClassChangeError","IndexOutOfBoundsException","InheritableThreadLocal","InstantiationError","InstantiationException","Integer","InternalError","InterruptedException","Iterable","LinkageError","Long","Math","NegativeArraySizeException","NoClassDefFoundError","NoSuchFieldError","NoSuchFieldException","NoSuchMethodError","NoSuchMethodException","NullPointerException","Number","NumberFormatException","Object","OutOfMemoryError","Override","Package","Process","ProcessBuilder","ProcessEnvironment","ProcessImpl","Readable","ReflectiveOperationException","Runnable","Runtime","RuntimeException","RuntimePermission","SafeVarargs","SecurityException","SecurityManager","Short","Shutdown","StackOverflowError","StackTraceElement","StrictMath","String","StringBuffer","StringBuilder","StringCoding","StringIndexOutOfBoundsException","SuppressWarnings","System","SystemClassLoaderAction","Terminator","Thread","ThreadDeath","ThreadGroup","ThreadLocal","Throwable","TypeNotPresentException","UnknownError"," UnsatisfiedLinkError","UnsupportedClassVersionError","UnsupportedOperationException","VerifyError","VirtualMachineError","Void");

	
	CompilationUnit javaParser = null;
	public CompilationUnit getJavaParser(){
		try {
			if (javaParser == null){
				try(FileInputStream input = new FileInputStream(file)) {
					javaParser = JavaParser.parse(input);
				} 
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
		return javaParser;
	}
	
	/**
	 * 替换引入
	 * @param oldImpl
	 * @param newImpl
	 * @throws Exception
	 */
	public void rpImp(String oldImpl , String newImpl){
		List<ImportDeclaration> implList = getJavaParser().getImports();
		if(implList == null){
			implList = new ArrayList<>();
		}
		
		List<ImportDeclaration> implFindList  = implList.stream().filter(e -> ((ImportDeclaration)e).getName().toString().equals(oldImpl) )
		        .collect(Collectors.toList());
		if (implFindList != null && implFindList.size() > 0){
			implList.remove(implFindList.get(0));
			if (newImpl != null){
				implList.add(new ImportDeclaration(new NameExpr(newImpl) , false , false));
			}
		}
		
		getJavaParser().setImports(implList);
		
	}
	
	/**
	 * 添加引入
	 * @param implSet
	 */
	public void addImpl(Set<String> implSet ){
		
		List<ImportDeclaration> implList = getJavaParser().getImports();
		if(implList == null){
			implList = new ArrayList<>();
		}
		
		Set<ImportDeclaration>  set = new HashSet<>();
		set.addAll(implList);
		
		implSet.stream()
        .forEach(e -> set.add(new ImportDeclaration(new NameExpr(e), false, false)));
		
		// 设置包
		getJavaParser().setImports(new ArrayList<>(set));
		
		
	}
	
	
	/**
	 * 根据前缀获取引入包
	 * @param prList
	 * @return
	 */
	public Set<String> findImpl(Set<String> prList){
		
		List<ImportDeclaration> implList = getJavaParser().getImports();
		if(implList == null){
			implList = new ArrayList<>();
		}
		
		Set<String> javaImplTemp = implList.stream()
				                           .map(e -> ((ImportDeclaration)e).getName().toString())
				                           .filter(e -> prList.stream().filter(p -> e.startsWith(p)).count() > 0)
				                           .collect(Collectors.toSet());
		
		return javaImplTemp;
	}
	
	
	/**
	 * 删除应用
	 * @param impl
	 */
	public void rmImp(String impl){
		rpImp(impl , null);
		
	}
	
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<String> findAllImplJava() throws Exception{
		
		Set<String> javaSet = new HashSet<>();
		
		new VoidVisitorAdapter() {
	        @Override
	        public void visit(MethodDeclaration n, Object arg) {
	        	
	        	n.getChildrenNodes().stream().filter(node -> node instanceof BlockStmt)
	        	.forEach(node ->javaSet.addAll(doFindJavaType(node )));
	        }
	    }.visit(getJavaParser(), null);
	    
	    javaSet.addAll(doFindJavaType(getJavaParser()));
	    
	    return javaSet;
	}
	
	/**
	 * 获取所有java类型
	 * @param n
	 * @param javaSet
	 */
	public Set<String> doFindJavaType(Node n  ){
		
		Set<String> javaSet = new HashSet<>();
		
		if(n instanceof ClassOrInterfaceType){
			String name = ((ClassOrInterfaceType) n).getName().trim();
			if (!name.contains(".")){
				javaSet.add(name);
			}
		}
		
		n.getChildrenNodes().forEach(e -> javaSet.addAll(doFindJavaType(e )));
		
		return javaSet;
	}
	

	/**
	 * 获取需要引入的类
	 * @return
	 */
	public Set<String> doFindImpl(Node n){
		
		return doFindJavaType(n).stream()
				                .filter(e -> !utilsList.contains(e))
				                .map(e -> findIm(e))
				                .filter(e -> e!= null)
				                .collect(Collectors.toSet());
		
	}
	
	
	/**
	 * 获取引入文件
	 * @param simpleName
	 * @return
	 * @throws Exception
	 */
	public String findIm(String simpleName){
		simpleName = simpleName.trim();
		if (utilsList.contains(simpleName)){
			return simpleName;
		}
		
		List<ImportDeclaration> implList = getJavaParser().getImports();
		if (implList == null ){
			throw new RuntimeException("not find " + simpleName);
		}
		
		for (ImportDeclaration impl : implList){
			if (((ImportDeclaration)impl).getName().toString().endsWith("." + simpleName.trim())){
				return impl.getName().toString();
			}
		}
		
		System.out.println("not find " + simpleName);
		return null;
//		throw new RuntimeException("not find " + simpleName);
	}
	
	
	/**
	 * 获取所有关于该节点的代码
	 * @param node
	 * @param name
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<Node> findNodeByBlock( String name){
		

		List<Node>  list = new ArrayList<>();
		
		new VoidVisitorAdapter() {
	        @Override
	        public void visit(MethodDeclaration n, Object arg) {
	        	
	        	List<Node> nList =  n.getChildrenNodes().stream().filter(node -> node instanceof BlockStmt && node.toString().contains(name))
	        	                                                 .collect(Collectors.toList());
	        	list.addAll(nList);
	        	
	        }
	    }.visit(getJavaParser(), null);
	    
	    return list;
	}
	
		
	
	 public static boolean checkNameExpr(Node node,NameExpr nameExpr){
	    	if (node.contains(nameExpr)){
	    		System.out.println("=nameExpr=======true");
	    		return true;
	    	}
	    	
	    	for(Node n : node.getChildrenNodes()){
	    		if (checkNameExpr(n ,nameExpr)){
	        		System.out.println("=checkNameExpr=======true");
	    			return true;
	    		}
	    		
	    	}
	    	
	    	return false;
	    	
	    }
	
	/**
	 * 寻找代码块中关于该变量的代码块
	 * @param metchNode
	 * @param varName
	 * @return
	 */
	public List<Node> findBlockByVal(Node metchNode , String varName ){
		
		return Start.find(metchNode, VariableDeclarationExpr.class).stream()
		         .filter(e -> e.toString().contains(" " + varName + "."))
		         .collect(Collectors.toList());
		
	}

}
